﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DepartmentManagement
{
    #region MiscFuntion
    /// <summary>
    /// 用来放置一些公用操作函数
    /// </summary>
    public static class MiscFunction
    {
        /// <summary>
        /// 获取当前使用数据库中表、视图结构，以便于数据库操作
        /// </summary>
        /// <returns>当前使用数据库中表、视图结构</returns>
        public static DataAccess.DatabaseType GetDatabaseSchema()
        {
            DataAccess.DatabaseType result = null;

            string appRoot = System.Windows.Forms.Application.StartupPath;
            string xmlFilePath = appRoot + @"\DataAccess\DatabaseSchema.xml";

            if(!System.IO.File.Exists(xmlFilePath))
                throw new Exception(@"Panic, database schema description file cannot be found. Please check if DataAccess\DatabaseSchema.xml exists.");

            System.Xml.Serialization.XmlSerializer xs=new System.Xml.Serialization.XmlSerializer(typeof(DataAccess.DatabaseType));

            using(System.IO.FileStream fs=new System.IO.FileStream(xmlFilePath,System.IO.FileMode.Open))
            {
                result=(DataAccess.DatabaseType)xs.Deserialize(fs);
            }

            return result;
        }

        /// <summary>
        /// 计算字符串的MD5值
        /// </summary>
        /// <param name="input">字符串</param>
        /// <returns>MD5值</returns>
        public static string ComputeMD5(string input)
        {
            string result = string.Empty;

            System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] inputData = System.Text.Encoding.ASCII.GetBytes(input);
            byte[] md5Data = md5.ComputeHash(inputData);

            for (int i = 0; i < md5Data.Length; i++)
            {
                result += md5Data[i].ToString("x").PadLeft(2, '0');
            }

            return result;
        }
    }
    #endregion

    #region CodingFunction
    public class CodingFunction
    {
        /// <summary>
        /// 对字符串进行QP编码
        /// </summary>
        /// <param name="srcString">字符串</param>
        /// <returns>QP编码</returns>
        public static string QPEncode(string srcString)
        {
            return QPEncode(srcString, System.Text.Encoding.Default);
        }

        /// <summary>
        /// 对字符串进行QP编码
        /// </summary>
        /// <param name="srcString">字符串</param>
        /// <param name="encoding">字符编码方式</param>
        /// <returns>QP编码</returns>
        public static string QPEncode(string srcString,System.Text.Encoding encoding)// QP编码
        {
            string Result = "";
            byte[] vBuffer = encoding.GetBytes(srcString);
            foreach (byte vByte in vBuffer)
                // 可见字符并非"="(#61)
                if ((vByte >= 33 && vByte <= 60) || (vByte >= 62 && vByte <= 126))
                    Result += (char)vByte;
                else Result += "=" + vByte.ToString("X2");
            return Result;
        }

        /// <summary>
        /// 对包含QP编码的字符串进行解码
        /// </summary>
        /// <param name="srcString">要解码的包含QP编码的字符串</param>
        /// <returns>已解码的字符串</returns>
        public static string QPDecode(string srcString)
        {
            return QPDecode(srcString, System.Text.Encoding.Default);
        }

        /// <summary>
        /// 对包含QP编码的字符串进行解码
        /// </summary>
        /// <param name="srcString">要解码的包含QP编码的字符串</param>
        /// <param name="encoding">字符编码方式</param>
        /// <returns>已解码的字符串</returns>
        public static string QPDecode(string srcString,System.Text.Encoding encoding)// 解码
        {
            System.Collections.ArrayList vBuffer = new System.Collections.ArrayList();

            for (int i = 0; i < srcString.Length; i++)
            {
                if (srcString[i] == '=')
                {
                    i++;
                    if (srcString[i] != '\r')
                    {
                        byte vByte;
                        if (byte.TryParse(srcString.Substring(i, 2),
                            System.Globalization.NumberStyles.HexNumber, null, out vByte))
                            vBuffer.Add(vByte);
                    }
                    i++;
                }
                else if (srcString[i] != '\n') vBuffer.Add((byte)srcString[i]);
            }
            return encoding.GetString((byte[])vBuffer.ToArray(typeof(byte)));
        }

        ///// <summary>
        ///// 一段连续的QP编码的字符串进行解码
        ///// </summary>
        ///// <param name="srcString">要解码的一段连续的QP编码的字符串</param>
        ///// <param name="encode">编码方式</param>
        ///// <returns>已解码的字符串</returns>
        //private static string seqQPDecode(string srcString, System.Text.Encoding encode)
        //{
        //    if (null == srcString || srcString.Equals(string.Empty))
        //        return string.Empty;

        //    if (srcString.StartsWith("="))
        //        srcString = srcString.Substring(1);

        //    string[] aHex = srcString.Split(new char[1] { '=' });
        //    byte[] abyte = new Byte[aHex.Length];

        //    for (int i = 0; i < abyte.Length; i++)
        //    {
        //        abyte[i] = (byte)int.Parse(aHex[i], System.Globalization.NumberStyles.HexNumber);
        //    }
        //    return encode.GetString(abyte);
        //}

        ///// <summary>
        ///// 对包含QP编码的字符串进行解码
        ///// </summary>
        ///// <param name="srcString">要解码的包含QP编码的字符串</param>
        ///// <param name="encode">字符编码方式，建议用Default</param>
        ///// <param name="nStart">开始解码的字符开始位置，一般为0</param>
        ///// <returns>已解码的字符串</returns>
        //public static string QPDecode(string srcString, System.Text.Encoding encode, long nStart)
        //{
        //    if (nStart >= srcString.Length) return srcString;

        //    //存放要解码的字符串
        //    StringBuilder sbHex = new StringBuilder();
        //    sbHex.Append(string.Empty);
        //    //存放已经解码过的字符串
        //    StringBuilder sbEncoded = new StringBuilder();
        //    sbEncoded.Append(string.Empty);
        //    //是否已经碰到QP的字符串
        //    bool isBegin = false;
        //    string temp;
        //    int i = (int)nStart;

        //    while (i < srcString.Length)
        //    {
        //        //初始化下次循环
        //        sbHex.Remove(0, sbHex.Length);
        //        isBegin = false;

        //        while (i < srcString.Length)
        //        {
        //            temp = srcString.Substring(i, 1);//还没有开始碰到第一个QP字符时每次取一个字符进行比较
        //            if (temp.StartsWith("="))
        //            {
        //                temp = srcString.Substring(i, 3);//对于以等号开始的每次取3个字符
        //                if (temp.EndsWith("\r\n"))//换行符
        //                {
        //                    if (isBegin)
        //                        break;
        //                    // sbEncoded.Append(string.Empty);
        //                    i = i + 3;
        //                }
        //                else if (!temp.EndsWith("3D"))
        //                {
        //                    sbHex.Append(temp);
        //                    isBegin = true;//已开始碰到第一个QP字符，放到QP缓冲区
        //                    i = i + 3;
        //                }
        //                else //如果是以3D结尾则该字符串只是一个等号，放到已解码缓冲区
        //                {
        //                    if (isBegin)
        //                        break;

        //                    sbEncoded.Append("=");
        //                    i = i + 3;
        //                }

        //            }
        //            else
        //            {
        //                if (isBegin)//已经取得整块的QP字符串，跳出该次循环
        //                    break;
        //                sbEncoded.Append(temp);//不是QP字符则放到已解码缓冲区中
        //                i++;
        //            }

        //        }
        //        //一次循环结束，把已经取得整块的QP字符串进行解码
        //        sbEncoded.Append(seqQPDecode(sbHex.ToString(), encode));
        //    }

        //    return sbEncoded.ToString();
        //}


        ///// <summary>
        ///// 对包含QP编码的字符串进行解码,用Default字符编码方式，从字符串开始位置进行解码
        ///// </summary>
        ///// <param name="srcString">要解码的包含QP编码的字符串</param>
        ///// <returns>已解码的字符串</returns>
        //public static string QPDecode(string srcString)
        //{
        //    if (null == srcString || srcString.Equals(string.Empty)) return srcString;

        //    return QPDecode(srcString, Encoding.Default, 0);

        //}

        /// <summary>
        /// Base64编码解码
        /// </summary>
        /// <param name="srcString">编码字符串</param>
        /// <returns>解码字符串</returns>
        public static string Base64Decode(string srcString)
        {
            return Base64Decode(srcString, System.Text.Encoding.Default);
        }

        /// <summary>
        /// Base64编码解码
        /// </summary>
        /// <param name="srcString">编码字符串</param>
        /// <param name="encoding">系统字符编码方式</param>
        /// <returns>解码字符串</returns>
        public static string Base64Decode(string srcString, System.Text.Encoding encoding)
        {
            if (null == srcString || string.Empty == srcString)
                return string.Empty;

            string result = string.Empty;
            Base64Decoder dc = new Base64Decoder();
            byte[] decodeTemp = dc.GetDecoded(srcString);
            result = encoding.GetString(decodeTemp);

            return result;
        }

        /// <summary>
        /// 字符串Base64编码
        /// </summary>
        /// <param name="srcString">需编码字符串</param>
        /// <returns>Base64编码</returns>
        public static string Base64Encode(string srcString)
        {
            return Base64Encode(srcString, System.Text.Encoding.Default);
        }

        /// <summary>
        /// 字符串Base64编码
        /// </summary>
        /// <param name="srcString">需编码字符串</param>
        /// <param name="encoding">系统字符编码方式</param>
        /// <returns></returns>
        public static string Base64Encode(string srcString, System.Text.Encoding encoding)
        {
            if (null == srcString || string.Empty == srcString)
                return string.Empty;

            string result = string.Empty;
            Base64Encoder ec = new Base64Encoder();
            result = ec.GetEncoded(encoding.GetBytes(srcString));

            return result;
        }

        #region Base64 Encode and Decode help class
        /// <summary>
        /// Base64编码类。
        /// 将byte[]类型转换成Base64编码的string类型。
        /// </summary>
        private class Base64Encoder
        {
            byte[] source;
            int length, length2;
            int blockCount;
            int paddingCount;
            public static Base64Encoder Encoder = new Base64Encoder();

            public Base64Encoder()
            {
            }

            private void init(byte[] input)
            {
                source = input;
                length = input.Length;
                if ((length % 3) == 0)
                {
                    paddingCount = 0;
                    blockCount = length / 3;
                }
                else
                {
                    paddingCount = 3 - (length % 3);
                    blockCount = (length + paddingCount) / 3;
                }
                length2 = length + paddingCount;
            }

            /// <summary>
            /// Base64编码
            /// </summary>
            /// <param name="input">输入字符序列</param>
            /// <returns>Base64字符串</returns>
            public string GetEncoded(byte[] input)
            {
                //初始化
                init(input);

                byte[] source2;
                source2 = new byte[length2];

                for (int x = 0; x < length2; x++)
                {
                    if (x < length)
                    {
                        source2[x] = source[x];
                    }
                    else
                    {
                        source2[x] = 0;
                    }
                }

                byte b1, b2, b3;
                byte temp, temp1, temp2, temp3, temp4;
                byte[] buffer = new byte[blockCount * 4];
                char[] result = new char[blockCount * 4];
                for (int x = 0; x < blockCount; x++)
                {
                    b1 = source2[x * 3];
                    b2 = source2[x * 3 + 1];
                    b3 = source2[x * 3 + 2];

                    temp1 = (byte)((b1 & 252) >> 2);

                    temp = (byte)((b1 & 3) << 4);
                    temp2 = (byte)((b2 & 240) >> 4);
                    temp2 += temp;

                    temp = (byte)((b2 & 15) << 2);
                    temp3 = (byte)((b3 & 192) >> 6);
                    temp3 += temp;

                    temp4 = (byte)(b3 & 63);

                    buffer[x * 4] = temp1;
                    buffer[x * 4 + 1] = temp2;
                    buffer[x * 4 + 2] = temp3;
                    buffer[x * 4 + 3] = temp4;

                }

                for (int x = 0; x < blockCount * 4; x++)
                {
                    result[x] = sixbit2char(buffer[x]);
                }


                switch (paddingCount)
                {
                    case 0: break;
                    case 1: result[blockCount * 4 - 1] = '='; break;
                    case 2: result[blockCount * 4 - 1] = '=';
                        result[blockCount * 4 - 2] = '=';
                        break;
                    default: break;
                }
                return new string(result);
            }

            private char sixbit2char(byte b)
            {
                char[] lookupTable = new char[64]{
                  'A','B','C','D','E','F','G','H','I','J','K','L','M',
                 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
                 'a','b','c','d','e','f','g','h','i','j','k','l','m',
                 'n','o','p','q','r','s','t','u','v','w','x','y','z',
                 '0','1','2','3','4','5','6','7','8','9','+','/'};

                if ((b >= 0) && (b <= 63))
                {
                    return lookupTable[(int)b];
                }
                else
                {

                    return ' ';
                }
            }

        }

        /// <summary>
        /// Base64解码类
        /// 将Base64编码的string类型转换成byte[]类型
        /// </summary>
        private class Base64Decoder
        {
            char[] source;
            int length, length2, length3;
            int blockCount;
            int paddingCount;
            public static Base64Decoder Decoder = new Base64Decoder();

            public Base64Decoder()
            {
            }

            private void init(char[] input)
            {
                int temp = 0;
                source = input;
                length = input.Length;

                for (int x = 0; x < 2; x++)
                {
                    if (input[length - x - 1] == '=')
                        temp++;
                }
                paddingCount = temp;

                blockCount = length / 4;
                length2 = blockCount * 3;
            }

            /// <summary>
            /// Base64解码
            /// </summary>
            /// <param name="strInput">Base64字符串</param>
            /// <returns>Base64编码字符序列</returns>
            public byte[] GetDecoded(string strInput)
            {
                //初始化
                init(strInput.ToCharArray());

                byte[] buffer = new byte[length];
                byte[] buffer2 = new byte[length2];

                for (int x = 0; x < length; x++)
                {
                    buffer[x] = char2sixbit(source[x]);
                }

                byte b, b1, b2, b3;
                byte temp1, temp2, temp3, temp4;

                for (int x = 0; x < blockCount; x++)
                {
                    temp1 = buffer[x * 4];
                    temp2 = buffer[x * 4 + 1];
                    temp3 = buffer[x * 4 + 2];
                    temp4 = buffer[x * 4 + 3];

                    b = (byte)(temp1 << 2);
                    b1 = (byte)((temp2 & 48) >> 4);
                    b1 += b;

                    b = (byte)((temp2 & 15) << 4);
                    b2 = (byte)((temp3 & 60) >> 2);
                    b2 += b;

                    b = (byte)((temp3 & 3) << 6);
                    b3 = temp4;
                    b3 += b;

                    buffer2[x * 3] = b1;
                    buffer2[x * 3 + 1] = b2;
                    buffer2[x * 3 + 2] = b3;
                }

                length3 = length2 - paddingCount;
                byte[] result = new byte[length3];

                for (int x = 0; x < length3; x++)
                {
                    result[x] = buffer2[x];
                }

                return result;
            }

            private byte char2sixbit(char c)
            {
                char[] lookupTable = new char[64]{  
                 'A','B','C','D','E','F','G','H','I','J','K','L','M','N',
                 'O','P','Q','R','S','T','U','V','W','X','Y', 'Z',
                 'a','b','c','d','e','f','g','h','i','j','k','l','m','n',
                 'o','p','q','r','s','t','u','v','w','x','y','z',
                 '0','1','2','3','4','5','6','7','8','9','+','/'};
                if (c == '=')
                    return 0;
                else
                {
                    for (int x = 0; x < 64; x++)
                    {
                        if (lookupTable[x] == c)
                            return (byte)x;
                    }

                    return 0;
                }

            }
        }
        #endregion
    }
    #endregion
}
